import re
from django.shortcuts import render ,redirect
from django.contrib.auth import login,authenticate,logout
from django.views import View
from django.contrib.auth import mixins
from django import http
from django_redis import get_redis_connection
from django.conf import settings
import json
from django.db import DatabaseError

from users.models import User, Address
from meiduo_mall.utils.response_code import RETCODE
from meiduo_mall.utils.views import LoginRequiredView
from celery_tasks.email.tasks import send_verify_email
from .utils import generate_verify_email_url,check_verify_email_token
import logging
logger = logging.getLogger('django')

class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """
        提供注册界面
        :param request: 请求对象
        :return: 注册界面
        """
        return render(request,'register.html')

    def post(self,request):
        """
        注册逻辑
        """
        #接受请求体表单数据
        query_dict = request.POST
        # 获取username password password2 mobile sms_code allow
        username = query_dict.get('username')
        password = query_dict.get('password')
        password2 = query_dict.get('password2')
        mobile = query_dict.get('mobile')
        sms_code_client = query_dict.get('sms_code')
        allow = query_dict.get('allow')
        # 没有指定复选框中的value 没勾为None 如果前端指定了value值勾选就传递value的值

        #校对
        # 判断可迭代对象中的每个元素是否有为1NOne ‘‘,{},[],False,如果有就返回False
        if all([username,password,password2,mobile,sms_code_client,allow]) is False:
            return  http.HttpResponseForbidden('缺少必要参数')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$',username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')

        if not re.match(r'^[0-9A-Za-z]{8,20}$',password):
            return  http.HttpResponseForbidden('请输入8-20位的密码')

        if password != password2 :
            return http.HttpResponseForbidden('两次密码输入不一致')

        if not re.match(r'^1[3-9]\d{9]$',mobile):
             return http.HttpResponseForbidden('请输入正确的手机号码')
        #  短信验证码后期补充
        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_code')
        # 获得短信验证码
        sms_code_server = redis_conn.get('sms_cod_%s' % mobile)
        # 让短信验证码只能用一次
        redis_conn.delete('sms_code_%s' % mobile)
        # 判断验证码是否过期
        if sms_code_server is None :
            return http.HttpResponseForbidden('短信验证码过期')
        # 判断用户短信验证码是否输入正确
        if sms_code_client != sms_code_server.decode():
            return http.HttpResponseForbidden('短信验证码输入有误')
        # 创建一个新用户
        # 方法一
        # user = User.objects.create(password=password)
        # user.set_password(password)
        # user.save()
        # 方法二
        user  = User.objects.create_user(username=username,password=password,mobile=mobile)
        # 状态保持
        login(request,user)
        #用户注册成功即代笔登陆成功
        # 响应，重定向到首页
        return http.HttpResponse('注册成功，跳转到首页')
        #响应,重定向到首页


# class UsernameCountView(View):
#     """判断用户是否重复注册"""
#
#     def get(self,request,username):
#         # 以username 查询user模型，再去取它的count,0:代表用户没有重复,1代表用户名有重复
#         count = User.objects.filter(username=username).count()
#         # 响应
#         return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','count':count})

class MobileCountView(View):
    """判断手机号码是否重复注册"""
    def get(self,request,mobile):
        # 以mobile查询user模型，再娶它的count,0:表示用户没有重复，1代表用户有重复
        count = User.objects.filter(mobile=mobile).count()
        # 响应
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','count':count})

class UsernameCountView(View):
    """判断用户是否是重复注册"""

    def get(self, request, username):
        # 以username查询user模型,再取它的count, 0:代表用户名没有重复, 1代表用户名重复
        count = User.objects.filter(username=username).count()
        # 响应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})



class LoginView(View):
    """"用户登录"""

    def get(self,request):
        return render(request,'login.html')
    """
    账号登陆一 不推荐
    def post(self,request):
    # 接收前端的表单数据
        query_dict = request.POST
        username = query_dict.get('username')
        password = query_dict.get('password')
        remembered = query_dict.get('remembered')

        # 校验
        user = User.objects.get(username=username)
        user.check_password(password)
        return user
        # 判断用户是否用手机登录，如果是的 认证时就用手机号查询
        if re.match(r'^1[3-9]\d{9}$',username):
            User.USERNAME_FIELD = 'mobile'
            
         # authemticate 用户认证 
        user = authenticate(request,username=username,password=password)
    
        User.USERNAME_FIELD = 'username' 
        # 再改回去 不然其他用户登陆可能会有问题
        # 判断用户是否通过认证
        if user is None :
            return render(request,'login.html',{'account_errmsg':'用户或密码错误'})
        # 状态保持
        login(request,user)
        # 如果用户没有记录登陆
        if remembered != 'on' :
            request.session.set_expiry(0)
        # 把session的过期时间设置为0会话结束就会过期
        # 三目法 request.session.set_expiry((60*60*48) if remembered else o)
        
        # 重定向到指定页
        return http.HttpResponse('登陆成功，来到首页')

    """


    def post(self,request):
        # 接收前端传入的表单数据
        query_dict = request.POST
        username = query_dict.get('username')
        password = query_dict.get('password')
        remembered = query_dict.get('remembered')

        # 校验
        # authenticate 用户认证
        user = authenticate(request,username=username,password=password)

        # 判断用户是否通过认证
        if user is None:
            return  render(request,'login.html',{'account_errmsg':'用户或密码错误'})
        # 状态保持
        login(request,user)
        # 如果用户没有记录登陆
        if remembered != 'on':
            request.session.set_expiry(0)
        # 把session的过期时间设置为0表示会话结束后就会过期

        # /login/?next=/info/
        # /login/
        # 用户如果有来源就重定向到来源,反之去首页
        response = redirect(request.GET.get('next') or '/' ) # 创建重定向响应对象 SESSION_COOKIE_AGE

        # response.set_cookie('username',user.usernamne,max_age=(60*60*24*7*2)if remembered else None)
        response.set_cookie('username',user.username,max_age=settings.SESSION_COOKIE_AGE if remembered else None)
        # print(settings.SESSION_COOKIE_AGE)
        # 重定向到指定页
        # return http.HttpResponse('登陆成功,来到首页')
        return response

class LogoutView(View):
    """退出登录"""

    def get(self,request):

        # 清楚状态保持
        logout(request)

        # 创建响应对象
        response = redirect('/login/')
        # 删除cookie中的username
        response.delete_cookie('username')
        # 重定向到登陆界面
        return response
#
# class InfoView(View):
#     """用户中心"""
#     def get(self,request):
#         # if isinstance(request.user,User)
#         if request.user.is_authenticated:
#             # 如果if成立说明是登陆用户
#             return render(request,'user_center_info.html')
#         else:
#             return render('/login/?next=/info/')

class InfoView(mixins.LoginRequiredMixin, View):
    """用户中心"""

    def get(self,request):
        return render(request,'user_center_info.html')



class EmailView(LoginRequiredView):
    """设置用户邮箱"""
    def put(self,request):
        # 接受数据
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 校验
        if email is None:
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$',email):
            return http.HttpResponseForbidden('邮件格式不正确')
        # 业务处理逻辑
        user = request.user
        # user.email = email
        # 此写法,在当前场景会随着重发邮箱时,重复设置邮箱
        # user.save()
        User.objects.filter(id=user.id,email='').update(email=email)
        # 邮箱只要设置成功了,此代码都是无效的修改


        # 在此顺带的发一个激活邮件出去
        # from django.core.mail import send_mail
        # send_mail(subject='主题',message='邮件普通正文',from_email='发件人',必须是列表,
        #           html_message='超文本的邮件内容')
        # verify_url = 'http://www.meiduo.site:8000/emails/verification/?token=3'


        # 生成激活url
        verify_url = generate_verify_email_url(user)
        # celery异步请求
        send_verify_email.delay(email,verify_url)
        # 响应
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

class VerifyEmailView(View):
    """激活用户邮箱"""
    def get(self,request):
        # 获取查询参数中的token
        token = request.GET.get('token')
        # 校验
        if token is None:
            return http.HttpResponseForbidden('缺少token')
        # 再对token进行解密，解密后根据里面的user_id,和email查询出亚激活的邮箱的那个User
        user = check_verify_email_token()
        if user is None:
            return http.HttpResponseForbidden('缺少token')
        #修改user的email_active字段 设置为True
        user.email_active = True
        user.save()

        # 响应
        return redirect('/info/')
        # return render(request,'user_center_info.html')


class AddressView(LoginRequiredView):
    """收获地址"""
    def get(self,request):
        user = request.user # 获取用户
        address_qs = Address.objects.filter(user=user,is_deleted=False)
        address_list = []  #用来装用户所有收货地址字典
        for address in address_qs:
            # 把新增的address模型对象转换成字典,并响应给前端
            address_dict = {
                'id' : address.id ,
                'title' : address.title,
                'receiver' : address.receiver,
                'province_id' : address.province_id,
                'province' : address.province.name,
                'city_id' : address.city_id,
                'city' : address.city.name,
                'district_id' : address.district_id,
                'district' : address.district.name,
                'palace' : address.place,
                'mobile' : address.mobile,
                'tel' : address.tel,
                'email' : address.email,
                # 'id': address.id,
                # 'title': address.title,
                # 'receiver': address.receiver,
                # 'province_id': address.province_id,
                # 'province': address.province.name,
                # 'city_id': address.city_id,
                # 'city': address.city.name,
                # 'district_id': address.district_id,
                # 'district': address.district.name,
                # 'place': address.place,
                # 'mobile': address.mobile,
                # 'tel': address.tel,
                # 'email': address.email,
            }
            # 添加收货地址字典到表中
            address_list.append(address_dict)
        # 包装模板进行渲染的数据
        context = {
            'addresses' : address_list,  #当前登录用户的所有收货地址[{},{}]
            'default_address_id' : user.default_address_id,# 当前用户默认收货地址id


        }
        return render(request,'user_center_site.html',context)

class CreateAddressView(LoginRequiredView):
    """收货地址新增"""
    def post(self,request):

        # 判断用户收货地址上限 不能多于20个
        user = request.user

        # 查询当前登录用户未逻辑删除的收货地址数量
        count = Address.objects.filter(user=user,is_deleted=False).count()
        # user.addresses.filter(is_deleted=False).count()
        if count >= 20:
            return http.JsonResponse({'code': RETCODE.MAXNUM,'errmsg':'收货地址超限'})

        # 接收请求体数据
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')


        # 校验
        if all([title,receiver,province_id,city_id,district_id,place,mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4}?$)',tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$',email):
                return http.HttpResponseForbidden('参数email')

        # try：
        #     Area.objects.get(id=province_id)

        try:
            address = Address.objects.create(
                user=user,
                title=title,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place = place,
                mobile =mobile,
                tel = tel,
                email = email
            )
        except DatabaseError as e :
            logger.error(e)
            return http.HttpResponseForbidden('添加收货地址失败')

        # 如果用户还没有默认收货地址，把当前的收货地址设置为用户的默认地址
        if user.default_address is None:
            user.default_address = address
            user.save()
        # 把新增的address模型对象转换成字典，并响应给前端
        address_dict ={
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,


        }
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'添加收货地址成功','address':address_dict})

class UpdateDestroAddressView(LoginRequiredView):
    """修改和删除收货地址"""
    def put(self,request,address_id):
        """修改收货地址逻辑"""
        # 对address_id进行校验
        try:
            address = Address.objects.get(id=address_id,user=request.user,is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('修改收货地址失败')

        # 接受请求体数据
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验
        if all([title, receiver, province_id, city_id, district_id, place, mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')


        # 修改
        try:

            # Address.objects.filter(id=address_id).update(
            #     title=title,
            #     receiver=receiver,
            #     province_id=province_id,
            #     city_id=city_id,
            #     district_id=district_id,
            #     place=place,
            #     mobile=mobile,
            #     tel=tel,
            #     email=email
            # )

            address.title=title,
            address.receiver=receiver,
            address.province_id=province_id,
            address.city_id=city_id,
            address.district_id=district_id,
            address.place=place,
            address.mobile=mobile,
            address.tel=tel,
            address.email=email,
            address.save()
        except DatabaseError as e:
            logger.error(e)
            return http.HttpResponseForbidden('修改收货地址')


        # 把新增的address模型对象转换成字典，并响应个前端
        address_dict={
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }

        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'修改收货地址成功','address':address_dict})

    def delete(eslf,request,address_id):
        """收货地址删除"""
        try:
            address = Address.objects.get(id=address_id,user=request.user,is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('删除收货地址失败')

        # address.delete()物理删除


        # 响应
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

class DefaulAddressView(LoginRequiredView):
    """设置用户默认收货地址"""
    def put(self,request,address_id):

        try:
            address = Address.objects.get(id=address_id,user=request.user,is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('设置默认收货地址失败')

        request.user.default_address = address  # 给用户的默认收货地址字段重新赋值
        request.user.save()

        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

class UpdateTitleAddressView(LoginRequiredView):
    """修改收货地址标题"""

    def put(self,requst,address_id):

        try:
            address = Address.objects.get(id=address_id,user=requst.user,is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('设置默认收货地址失败')

        json_dict = json.loads(requst.body.decode())
        title = json_dict.get('title')

        if title is None:
            return http.HttpResponseForbidden('缺少必须传参数')

        # 修改当前收货地址标题
        address.title = title
        address.save()

        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

class ChangePasswordView(LoginRequiredView):
    """修改用户登录密码"""

    def get(self,request):
        return render(request,'user_center_pass.html')

    def post(self,request):
        # 接受表单数据
        query_dict = request.POST
        old_pwd = query_dict.get('old_pwd')
        new_pwd = query_dict.get('new_pwd')
        new_pwd = query_dict.get('new_cpwd')

        user = request.user
        # 校验
        if all([old_pwd,new_pwd,new_pwd]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        if user.check_password(old_pwd) is False:
            return render(request,'user_center_pass.html',{'origin_pwd_errmsg':'原始密码不正确'})

        if not re.match(r'^[0-9A-Za-z]{8,20}',new_pwd):
            return http.HttpResponseForbidden('请输入8-20位长度的密码')
        if new_pwd != new_pwd:
            return http.HttpResponseForbidden('两次密码输入不一致')

        # 修改用户用户密码
        user.set_password(new_pwd)
        user.save()

        # 重定向到login
        return redirect('/logout/')